package com.dys.util;

import com.alibaba.druid.pool.DruidDataSource;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * @className: com.dys.util.DatabaseUtil
 * @description: 使用Apache提供的DBUtils进行数据库的操作
 * @author: pine cone
 * @version: v1.0.0
 * @createTime: 2024/09/12 下午8:41
 */
public class DatabaseApacheUtils {

    private static final Properties PROP = new Properties();
    private static final DruidDataSource DATA_SOURCE = new DruidDataSource();

    /**
     * 提供返回DataSource的静态方法
     *
     * @return
     */
    public static DataSource getDataSource() {
        return DATA_SOURCE;
    }

    /**
     * 采用ThreadLocal的方式，ThreadLocal可以将Connection对象在Service层获取，并且存储到ThreadLocal中，
     * 当Dao层需要和数据库交互时，优先从ThreadLocal中尝试获取Connection对象。
     */
    private static final ThreadLocal<Connection> TL = new ThreadLocal<>();

    // 加载database.properties文件。 同时将信息设置给dataSource
    static {
        try {
            // 优先通过PROP对象，加载database.properties文件
            InputStream is = DatabaseUtils.class.getResourceAsStream("/database.properties");
            PROP.load(is);
            // 给dataSource设置四个核心信息
            DATA_SOURCE.setDriverClassName(PROP.getProperty("jdbc.driverClassName"));
            DATA_SOURCE.setUrl(PROP.getProperty("jdbc.url"));
            DATA_SOURCE.setUsername(PROP.getProperty("jdbc.username"));
            DATA_SOURCE.setPassword(PROP.getProperty("jdbc.password"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 2.与MySQL建立连接,获取连接对象-->解决不是同一个Connection对象的问题
     *
     * @return 连接对象
     */
    public static Connection getConnection() {
        // 1、先尝试从ThreadLocal中获取。
        Connection conn = TL.get();
        if (conn == null) {
            // 2、没获取到，基于DriverManager获取Connection，然后添加到ThreadLocal中
            try {
                // 基于连接池获取Connection对象
                conn = DATA_SOURCE.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException("获取Connection连接出错!!!");
            }
            TL.set(conn);
        }

        // 3、获取到了，直接返回
        return conn;
    }

    /**
     * 3.针对写操作的释放资源
     *
     * @param conn 释放连接对象
     * @param stmt 释放发送SQL的对象
     */
    public static void closeAll(Connection conn, Statement stmt) {
        try {
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
                TL.remove();
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("关闭连接失败!!!");
        }
    }

    /**
     * 3.针对查询操作的释放资源
     *
     * @param conn 释放连接对象
     * @param stmt 释放发送SQL的对象
     * @param rs   释放查询对象
     */
    public static void closeAll(Connection conn, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (stmt != null) {
                stmt.close();
            }
            if (conn != null) {
                conn.close();
                TL.remove();
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException("关闭连接失败!!!");
        }
    }

    /**
     * 开启事务
     */
    public static void beginCommit() {
        Connection conn = getConnection();
        try {
            conn.setAutoCommit(false);
        } catch (SQLException e) {
            throw new RuntimeException("开启事务失败!");
        }
    }

    /**
     * 提交事务
     */
    public static void commit() {
        Connection conn = getConnection();
        try {
            conn.commit();
        } catch (SQLException e) {
            throw new RuntimeException("提交事务失败!");
        } finally {
            closeAll(conn, null);
        }
    }

    /**
     * 回滚事务
     */
    public static void rollback() {
        Connection conn = getConnection();
        try {
            conn.rollback();
        } catch (SQLException e) {
            throw new RuntimeException("回滚事务失败!");
        } finally {
            closeAll(conn, null);
        }
    }
}
